package cn.jtfadmin.base.lang.config.statuscode;

import cn.jtfadmin.base.lang.config.WebConfig;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Path;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 参数错误
 *
 * @author jtf
 * @see StatusCodeConfig
 * @see StatusCodeManager
 * @see WebConfig#configureHandlerExceptionResolvers(List)
 * @since 0.0.1
 */
@Component
public class ParamErrorStatusCodeConfig implements ExceptionStatusCodeConfig {

    /**
     * 参数错误
     */
    public static final Integer ERROR = 502;
    public static final String ERROR_MSG = "参数错误";


    public static final ExceptionStatusDescribe DEFAULT_ERROR_STATUS_DESCRIBE =
            new ExceptionStatusDescribe(ERROR_MSG, ERROR, MethodArgumentNotValidException.class, ConstraintViolationException.class,
                    IllegalArgumentException.class) {
                @Override
                public String getDescribe(Throwable throwable) {
                    List<Throwable> cause = ExceptionStatusCodeConfig.getCause(throwable);
                    for (Throwable ex : cause) {
                        List<String> message = new ArrayList<>();
                        // 参数绑定失败
                        if (ex instanceof MethodArgumentNotValidException) {
                            MethodArgumentNotValidException methodArgumentNotValidException = MethodArgumentNotValidException.class.cast(ex);
                            BindingResult bindingResult = methodArgumentNotValidException.getBindingResult();
                            List<FieldError> fieldErrors = bindingResult.getFieldErrors();
                            for (FieldError fieldError : fieldErrors) {
                                String field = fieldError.getField();
                                String defaultMessage = fieldError.getDefaultMessage();
                                message.add(field + defaultMessage);
                            }
                            List<ObjectError> globalErrors = bindingResult.getGlobalErrors();
                            for (ObjectError globalError : globalErrors) {
                                String objectName = globalError.getObjectName();
                                String defaultMessage = globalError.getDefaultMessage();
                                message.add(objectName + defaultMessage);
                            }
                            return StringUtils.collectionToDelimitedString(message, System.lineSeparator());
                        }
                        // spring validator 验证失败
                        if (ex instanceof ConstraintViolationException) {
                            ConstraintViolationException e = (ConstraintViolationException) ex;
                            Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
                            for (ConstraintViolation<?> constraintViolation : constraintViolations) {
                                Path propertyPath = constraintViolation.getPropertyPath();
                                message.add(propertyPath + constraintViolation.getMessage());
                            }
                            return StringUtils.collectionToDelimitedString(message, System.lineSeparator());
                        }
                        if (ex instanceof IllegalArgumentException) {
                            IllegalArgumentException illegalArgumentException = IllegalArgumentException.class.cast(ex);
                            return illegalArgumentException.getMessage();
                        }
                    }

                    return super.getDescribe(throwable);
                }
            };

    @Override
    public Set<ExceptionStatusDescribe> getExStatusDecribes() {
        Set<ExceptionStatusDescribe> set = new HashSet<>();
        set.add(DEFAULT_ERROR_STATUS_DESCRIBE);
        return set;
    }


}
